package codeGeneration;

import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

import util.Common;

import lexer.TokenConstant;

public class ViewLayerGenerator extends Generator {
	private List<Control> controls;
	private List<Event> events;
	private String actionFormName;
	private String viewPath;
	private String beanName;
	private FileWriter fileWriter;
	private String viewName;
	private String linkCalled;

	public ViewLayerGenerator(String viewPath, String viewName) {
		this.viewPath = viewPath;
		this.viewName = viewName;

		linkCalled = "add";
	}

	public void setActionForm(ActionForm actionForm) {
		this.controls = actionForm.getControls();
		actionFormName = actionForm.getName();
		beanName = actionForm.getBeanName();
	}

	public List<Event> getEvents() {
		return events;
	}

	public void setEvents(List<Event> events) {
		this.events = events;
	}

	public ViewLayerGenerator() {
		super();
	}

	public void generateControls() throws IOException {
		if (controls == null) {
			throw new IOException("Don't have any control to generate");
		}

		try {
			fileWriter = getFileWriter(viewPath + '/' + viewName + ".jsp");
		} catch (IOException e) {
			throw new IOException("Generate view failed. "
					+ "Can't interact with file");
		}

		try {
			generateInitOfView();
			generateHTML();
		} catch (IOException e) {
			e.printStackTrace();
			throw new IOException("Can't generate view layer file");
		}
		closeFileWriter(fileWriter);
	}

	private void generateTypeOfControl(FileWriter fileWriter, int type,
			String description, Properties prop) throws IOException {
		StringBuffer sbuff = new StringBuffer();
		if (description != null)
			appendToFile(fileWriter, "<!--" + description + " -->\n");

		switch (type) {
		case TokenConstant.TEXTFIELD:
			sbuff.append("<form:input");
			break;
		case TokenConstant.PASSWORD:
			sbuff.append("<form:password");
			break;
		case TokenConstant.BUTTON:
			sbuff.append("<input type=\"button\"");
			break;
		case TokenConstant.SUBMIT:
			sbuff.append("<input type=\"submit\"");
			break;
		case TokenConstant.RADIOBUTTON:
			sbuff.append("<form:radiobutton");
			break;
		case TokenConstant.CHECKBOX:
			sbuff.append("<form:checkbox");
			break;
		case TokenConstant.CHECKBOXES:
			sbuff.append("<form:checkboxes");
			break;
		case TokenConstant.HIDDEN:
			sbuff.append("<form:hidden");
			break;
		case TokenConstant.RADIOBUTTONS:
			sbuff.append("<form:radiobuttons");
			break;
		case TokenConstant.SELECT:
			sbuff.append("<form:select");
			break;
		case TokenConstant.TEXTAREA:
			sbuff.append("<form:textarea");
			break;
		case -1:
			sbuff.append("<form:errors");
			break;
		}
		indentOneTime(sbuff.toString(), prop, "/>", fileWriter, true);
	}

	private void generateInitOfView() throws IOException {
		fileWriter
				.append("<%@ taglib uri=\"http://java.sun.com/jsp/jstl/core\" prefix=\"c\" %>\n");
		fileWriter
				.append("<%@ taglib uri=\"http://www.springframework.org/tags/form\" prefix=\"form\"%>\n");
		fileWriter.append("<%@ page session=\"false\" %>\n");
		fileWriter.append("<%@ page pageEncoding=\"UTF-8\" %>\n");
	}

	private void generateHTML() throws IOException {
		indentOneTime("<html", null, ">", fileWriter, false);

		generateHead();
		generateBody();

		decreaseIndentOneTime("</html>", fileWriter);
	}

	private void generateHead() throws IOException {
		indentOneTime("<head>", null, "", fileWriter, false);
		generateCss();
		generateTitle(actionFormName);
		decreaseIndentOneTime("</head>", fileWriter);
	}

	private void generateCss() throws IOException {
		Properties prop = new Properties();
		prop.put("type", "text/css");

		indentOneTime("<style", prop, ">", fileWriter, false);
		indentOneTime(".cssError {", null, "", fileWriter, false);
		appendToFile(fileWriter, "color: #ff0000;\n");
		appendToFile(fileWriter, "padding-left: 15px;\n");
		appendToFile(fileWriter, "font-weight: bold;\n");
		decreaseIndentOneTime("}", fileWriter);

		decreaseIndentOneTime("</style>", fileWriter);
	}

	private void generateTitle(String title) throws IOException {
		indentOneTime("<title>", null, "", fileWriter, false);
		appendToFile(fileWriter, title + '\n');
		decreaseIndentOneTime("</title>", fileWriter);
	}

	private void generateBody() throws IOException {
		indentOneTime("<body>", null, "", fileWriter, false);
		generateForm(fileWriter);
		decreaseIndentOneTime("</body>", fileWriter);
	}

	private void generateForm(FileWriter fileWriter) throws IOException {
		Properties prop = new Properties();
		prop.put("method", "post");
		prop.put("action", linkCalled);
		prop.put("name", actionFormName);
		prop.put("commandName", Common.convertFirstLetterToLowerCase(beanName));

		indentOneTime("<form:form", prop, ">", fileWriter, false);
		generateTable(fileWriter);

		decreaseIndentOneTime("</form:form>", fileWriter);
	}

	private void generateTable(FileWriter fileWriter) throws IOException {
		indentOneTime("<table>", null, "", fileWriter, false);
		for (Control c : controls) {
			generateTableRow(fileWriter, c);
		}
		decreaseIndentOneTime("</table>", fileWriter);
	}

	private void generateTableRow(FileWriter fileWriter, Control c)
			throws IOException {
		indentOneTime("<tr>", null, "", fileWriter, false);
		appendToFile(fileWriter, "<td></td>\n");

		Properties prop = new Properties();
		boolean isHasError = false;

		if (c.getType() != TokenConstant.SUBMIT
				&& c.getType() != TokenConstant.BUTTON) {
			prop.put("path", c.getControlName());
			isHasError = true;
		}

		if (c.getValue() != null) {
			if (c.getType() == TokenConstant.CHECKBOXES
					|| c.getType() == TokenConstant.RADIOBUTTONS
					|| c.getType() == TokenConstant.SELECT)
				prop.put("item", "${" + c.getValue() + "}");

			else
				prop.put("value", c.getValue());
		}
		generateTableData(fileWriter, c.getDescription(), c.getType(), prop,
				isHasError);

		decreaseIndentOneTime("</tr>", fileWriter);
	}

	private void generateTableData(FileWriter fileWriter, String description,
			int type, Properties prop, boolean isError) throws IOException {
		indentOneTime("<td>", null, "", fileWriter, false);
		generateTypeOfControl(fileWriter, type, description, prop);

		if (isError) {
			prop.remove("value");
			prop.put("class", "cssError");
			generateTypeOfControl(fileWriter, -1, null, prop);
		}

		decreaseIndentOneTime("</td>", fileWriter);
	}

	public String getLinkCalled() {
		return linkCalled;
	}

	public void setLinkCalled(String linkCalled) {
		this.linkCalled = linkCalled;
	}
}
